﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using System.Text.RegularExpressions;

namespace Workflows.Components.ETL
{
    /// <summary>
    /// 
    /// </summary>
    public partial class CitationParserEditor : Form, IComponentEditor
    {
        private object _ActivityNode;
        private CitationParserComponent _CitationParser;

        /// <summary>
        /// 
        /// </summary>
        public CitationParserEditor()
        {
            InitializeComponent();
        }

        private void CitationParserEditor_Load(object sender, EventArgs e)
        {
            this.cbo_ParsingAlgorithms.Items.Clear();
            foreach(var mode in Enum.GetValues(typeof(CitationParserAlgorithms)))
            {
                this.cbo_ParsingAlgorithms.Items.Add(mode.ToString());
            }
        }

        #region Implementation of IComponentEditor

        public event UpdateComponentSettings UpdateComponentSettingEvent;

        /// <summary></summary>
        public object OwnerActivityNode
        {
            get { return _ActivityNode; }
            set { _ActivityNode = value; }
        }

        /// <summary></summary>
        public Type WorkflowComponentType
        {
            get { return typeof(CitationParserComponent); }
        }

        /// <summary></summary>
        public void LoadSettings(GlobalVariable[] globalVars, WorkflowComponentBase[] fromComponents, object activityNode, WorkflowComponentBase wfComponent)
        {
            this._ActivityNode = activityNode;
            this._CitationParser = (CitationParserComponent) wfComponent;

            CitationParserInstruction instruction = (CitationParserInstruction) this._CitationParser.Instruction;
            this.txt_ConnStr.Text = instruction.ConnStr;
            this.rt_SQL.Text = instruction.SQL;
            this.PopulateSrcTableFields(instruction.ConnStr, instruction.SQL);
            this.SelectComboxValue(this.cbo_KeyField, instruction.KeyField);
            this.SelectComboxValue(this.cbo_CiteTextField, instruction.CitationField);
            this.SelectComboxValue(this.cbo_CiteTimeField, instruction.CitationTimeField);
            this.PopulateTables(instruction.ConnStr);
            this.SelectComboxValue(this.cbo_OutputTable, instruction.OutputTable);
            this.SelectComboxValue(this.cbo_SrcKey, instruction.SrcKeyField);
            this.SelectComboxValue(this.cbo_PubTime, instruction.PubTimeField);
            this.SelectComboxValue(this.cbo_Title, instruction.TitleField);
            this.SelectComboxValue(this.cbo_Title2, instruction.BookTitleMeetingField);
            this.SelectComboxValue(this.cbo_Authors, instruction.AuthorsField);
            this.SelectComboxValue(this.cbo_Journal, instruction.JournalNameField);
            this.SelectComboxValue(this.cbo_Volume, instruction.VolumeField);
            this.SelectComboxValue(this.cbo_Issue, instruction.IssueField);
            this.SelectComboxValue(this.cbo_Page, instruction.PageField);
            this.SelectComboxValue(this.cbo_WosItemID, instruction.WosItemIDField);
            this.SelectComboxValue(this.cbo_ParsingAlgorithms, instruction.Algorithm.ToString());
        }

        private void PopulateSrcTableFields(string connStr, string sql)
        {
            this.cbo_KeyField.Items.Clear();
            this.cbo_CiteTimeField.Items.Clear();
            this.cbo_CiteTextField.Items.Clear();

            if(string.IsNullOrEmpty(connStr) || string.IsNullOrEmpty(sql))
                return;

            TableColumn[] cols = DbUtil.GetTableColumns(
                DataProviderType.MSSQL, connStr, sql);
            if(cols !=null && cols.Length>0)
            {
                foreach(TableColumn col in cols)
                {
                    this.cbo_KeyField.Items.Add(col.ColumnName);
                    this.cbo_CiteTimeField.Items.Add(col.ColumnName);
                    this.cbo_CiteTextField.Items.Add(col.ColumnName);
                }
            }
        }

        private void PopulateTables(string connStr)
        {
            this.cbo_OutputTable.Items.Clear();
            if(string.IsNullOrEmpty(connStr))
                return;
            string[] tblNames = DbUtil.GetTableNames(DataProviderType.MSSQL, "dbo", connStr);
            if(tblNames !=null && tblNames.Length>0)
            {
                foreach(string tblName in tblNames)
                {
                    this.cbo_OutputTable.Items.Add(tblName);
                }
            }
        }

        private void SelectComboxValue(ComboBox comboBox, string value)
        {
            if(comboBox.Items.Count>0 && !string.IsNullOrEmpty(value))
            {
                for(int i=0;i<comboBox.Items.Count;i++)
                {
                    if(comboBox.Items[i].ToString()==value)
                    {
                        comboBox.SelectedIndex = i;
                        break;
                    }
                }
            }
        }

        /// <summary></summary>
        public void SaveSettings()
        {
            CitationParserInstruction instruction = (CitationParserInstruction) this._CitationParser.Instruction;
            instruction.ConnStr = this.txt_ConnStr.Text;
            instruction.SQL = this.rt_SQL.Text;
            instruction.KeyField = this.cbo_KeyField.Text;
            instruction.CitationField = this.cbo_CiteTextField.Text;
            instruction.CitationTimeField = this.cbo_CiteTimeField.Text;
            instruction.OutputTable = this.cbo_OutputTable.Text;
            instruction.SrcKeyField = this.cbo_SrcKey.Text;
            instruction.PubTimeField = this.cbo_PubTime.Text;
            instruction.TitleField = this.cbo_Title.Text;
            instruction.BookTitleMeetingField = this.cbo_Title2.Text;
            instruction.AuthorsField = this.cbo_Authors.Text;
            instruction.JournalNameField = this.cbo_Journal.Text;
            instruction.VolumeField = this.cbo_Volume.Text;
            instruction.IssueField = this.cbo_Issue.Text;
            instruction.PageField = this.cbo_Page.Text;
            instruction.WosItemIDField = this.cbo_WosItemID.Text;
            instruction.Algorithm = CitationParserAlgorithms.DecisionTree;
            if (this.cbo_ParsingAlgorithms.SelectedIndex >= 0)
                instruction.Algorithm = (CitationParserAlgorithms)
                                        Enum.Parse(typeof (CitationParserAlgorithms), this.cbo_ParsingAlgorithms.Text);

            this._CitationParser.Instruction = instruction;
        }

        /// <summary></summary>
        public TestResult Test()
        {
            if(string.IsNullOrEmpty(this.rt_CitationText.Text))
            {
               return new TestResult(false, "Enter citation text"); 
            }
            else
            {
                try
                {
                    CitationParserWorker worker = new CitationParserWorker();
                    CitationParserInstruction instruction = (CitationParserInstruction) this._CitationParser.Instruction;
                    worker.SetInstruction(Guid.NewGuid(), instruction,
                                          "Citation Parser worker", "Citation parser");
                    Citation cite = new Citation();
                    bool canExtract = false;
                    //CitationAPAStyles apaStyles=new CitationAPAStyles();
                    //CitationMLAStyles mlaStyles=new CitationMLAStyles();
                    // bool canExtract = worker.ExtractCitation(this.rt_CitationText.Text, ref cite, apaStyles, mlaStyles);
                    if(instruction.Algorithm==CitationParserAlgorithms.Paracite && 
                        worker.ExtractCitation(this.rt_CitationText.Text, ref cite))
                    {
                        canExtract = true;
                        if (string.IsNullOrEmpty(cite.Journal))
                            throw new Exception("Unable to find journal name");
                    }
                    else if(instruction.Algorithm==CitationParserAlgorithms.DecisionTree && 
                        worker.ExtractCitationUsingDecisionTree(this.rt_CitationText.Text, ref cite))
                    {
                        canExtract = true;
                    }
                    else
                    {
                        return new TestResult(false, "Unable to parse");
                    }
                    if(canExtract)
                    {
                        this.txt_PubTime.Text = cite.PubTime;
                        this.txt_Title.Text = cite.Title;
                        this.txt_Title2.Text = cite.BookTitleOrMeetingName;
                        this.txt_Authors.Text = cite.Authors;
                        this.txt_Journal.Text = cite.Journal;
                        this.txt_Volume.Text = cite.Volume;
                        this.txt_Issue.Text = cite.Issue;
                        this.txt_Page.Text = cite.Pages;
                        return new TestResult(true,"Succeed");
                    }
                    else
                    {
                        return new TestResult(false, "Unable to extract");
                    }
                }
                catch(Exception ex)
                {
                    return new TestResult(false, ex.Message);
                }
            }
        }

        #endregion

        private void btn_ParseSql_Click(object sender, EventArgs e)
        {
            this.PopulateSrcTableFields(this.txt_ConnStr.Text, this.rt_SQL.Text);
        }

        private void btn_Refresh_Click(object sender, EventArgs e)
        {
            this.PopulateTables(this.txt_ConnStr.Text);
        }

        private void cbo_OutputTable_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_OutputTable.SelectedIndex>=0)
            {
                string connStr = this.txt_ConnStr.Text;
                string tblName = this.cbo_OutputTable.SelectedItem.ToString();
                TableColumn[] cols = DbUtil.GetTableColumns(
                    DataProviderType.MSSQL, connStr, "dbo", tblName);
                this.cbo_SrcKey.Items.Clear();
                this.cbo_PubTime.Items.Clear();
                this.cbo_Title.Items.Clear();
                this.cbo_Title2.Items.Clear();
                this.cbo_Authors.Items.Clear();
                this.cbo_Journal.Items.Clear();
                this.cbo_Volume.Items.Clear();
                this.cbo_Issue.Items.Clear();
                this.cbo_Page.Items.Clear();
                this.cbo_WosItemID.Items.Clear();

                if(cols !=null && cols.Length>0)
                {
                    foreach(TableColumn col in cols)
                    {
                        this.cbo_SrcKey.Items.Add(col.ColumnName);
                        this.cbo_PubTime.Items.Add(col.ColumnName);
                        this.cbo_Title.Items.Add(col.ColumnName);
                        this.cbo_Title2.Items.Add(col.ColumnName);
                        this.cbo_Authors.Items.Add(col.ColumnName);
                        this.cbo_Journal.Items.Add(col.ColumnName);
                        this.cbo_Volume.Items.Add(col.ColumnName);
                        this.cbo_Issue.Items.Add(col.ColumnName);
                        this.cbo_Page.Items.Add(col.ColumnName);
                        this.cbo_WosItemID.Items.Add(col.ColumnName);
                    }
                }
            }
        }

        private void btn_Extract_Click(object sender, EventArgs e)
        {
            this.SaveSettings();
            TestResult result = this.Test();
            if(!result.Succeed)
            {
                MessageBox.Show(result.Message);
            }
        }

        private void btn_OK_Click(object sender, EventArgs e)
        {
            this.SaveSettings();
            if (this.UpdateComponentSettingEvent != null)
                this.UpdateComponentSettingEvent(this._ActivityNode, this._CitationParser);
            this.Close();
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btn_Link_Click(object sender, EventArgs e)
        {
            try
            {
                List<string> authorNames = WosLinker.SplitAuthors(txt_Authors.Text);
                
                int pubYear;
                bool canParseYear = int.TryParse(this.txt_PubTime.Text, out pubYear);
                if (!canParseYear)
                {
                    DateTime pubTime;
                    bool hasPubTime = DateTime.TryParse(this.txt_PubTime.Text, out pubTime);
                    if (hasPubTime)
                        pubYear = pubTime.Year;
                }
                Range<int> pages = WosLinker.SplitPages(txt_Page.Text);
                
                WosItem wosItem =
                    WosLinker.FindLinkedWosItem(
                    authorNames, txt_Journal.Text,
                    txt_Volume.Text,
                    txt_Issue.Text,
                    txt_Title.Text,
                    pubYear, pages);
                if (wosItem != null)
                {
                    this.txt_WosItemID.Text = wosItem.SourceItemID.ToString();
                    this.txt_WosJournal.Text = wosItem.JournalName;
                    this.txt_WosTitle.Text = wosItem.Title;
                    this.txt_WosAuthors.Text = wosItem.Authors;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}
